#include "regex.h"

static char* GetPrintChar(int iMin, int iMax);
static char* get_regex_str(struct regex_group_t* pstRegex);
static void make_print_info(struct regex_group_t* pstRegex, struct regex_group_print_info* pstPrintInfo, int* piInfoCnt, int iLevel, int iPos);
static int ComparePrintInfo(const void* pvInfo1, const void* pvInfo2);

static char* GetPrintChar(int iMin, int iMax)
{
    static char acStr[32]; 

    memset(acStr, 0, sizeof(acStr));

    if (iMin == 0 && iMax == 0)
    {
        return "*";
    } 
    else if (iMin == 1 && iMax == 0)
    {
        return "+";
    } 
    else if (iMin == 0 && iMax == 1)
    {
        return "?";
    } 
    else if (iMin == 1 && iMax == 1)
    {
        return "";
    } 
    else
    {
        sprintf(acStr, "{%d,%d}", iMin, iMax);
        return acStr;
    } 
} 

// print regex according to regex analyse result 
void print_regex(struct regex_group_t* pstRegex)
{
    int iJ = 0;
    int iM = 0; 
    char acStr[256];
    struct regex_list_t* pstCurRegexList = NULL;

    if (pstRegex == NULL)
    {
        return;
    } 

    pstCurRegexList = pstRegex->pstRegList;
    while (pstCurRegexList)
    {
        memset(acStr, 0, sizeof(acStr));
        iM = 0;
        for (iJ = 0; iJ < 256; iJ++)
        {
            if (pstCurRegexList->stRegex.acStr[iJ] == 1)
            {
                acStr[iM++] = iJ;
            } 
        } 
        if (iM > 1)
        {
            printf("[");
        } 
        printf("%s", acStr);
        if (iM > 1)
        {
            printf("]");
        } 
        printf("%s", GetPrintChar(pstCurRegexList->stRegex.iMin, pstCurRegexList->stRegex.iMax));

        pstCurRegexList = pstCurRegexList->pstNext;
    } 
    if (pstRegex->iReferBackNo > 0)
    {
        printf("\\%d", pstRegex->iReferBackNo);
    } 

    if (pstRegex->pstChild)
    {
        printf("(");
        print_regex(pstRegex->pstChild);
        printf(")");
        printf("%s", GetPrintChar(pstRegex->iMin, pstRegex->iMax));
    } 

    if (pstRegex->cOr == TRUE)
    {
        printf("|");
    } 

    if (pstRegex->pstBrother)
    {
        print_regex(pstRegex->pstBrother);
    } 

    return;
} 

static char* get_regex_str(struct regex_group_t* pstRegex)
{
    int iJ = 0;
    int iM = 0;
    char acStr[255+1];
    static char acRegex[1024];
    struct regex_list_t* pstCurRegexList = NULL;

    memset(acRegex, 0, sizeof(acRegex));

    strcat(acRegex, "(");
    pstCurRegexList = pstRegex->pstRegList;
    while (pstCurRegexList)
    {
        memset(acStr, 0, sizeof(acStr));
        iM = 0;
        for (iJ = 1; iJ < 256; iJ++)
        {
            if (pstCurRegexList->stRegex.acStr[iJ] == 1)
            {
                acStr[iM++] = iJ;
            } 
        } 
        if (iM > 1)
        {
            strcat(acRegex, "[");
        } 
        strcat(acRegex, acStr);
        if (iM > 1)
        {
            strcat(acRegex, "]");
        } 
        strcat(acRegex, GetPrintChar(pstCurRegexList->stRegex.iMin, pstCurRegexList->stRegex.iMax));

        pstCurRegexList = pstCurRegexList->pstNext;
    } 
    if (pstRegex->iReferBackNo > 0)
    {
        printf("\\%d", pstRegex->iReferBackNo);
    } 
    strcat(acRegex, ")");

    strcat(acRegex, GetPrintChar(pstRegex->iMin, pstRegex->iMax));
    if (pstRegex->cOr == TRUE)
    {
        strcat(acRegex, "|");
    } 

    return acRegex;
} 

static void make_print_info(
        struct regex_group_t* pstRegex, 
        struct regex_group_print_info* pstPrintInfo, 
        int* piInfoCnt, 
        int iLevel,
        int iPos)
{
    if (pstRegex == NULL)
    {
        return;
    } 

    pstPrintInfo[*piInfoCnt].pstRegex = pstRegex;
    pstPrintInfo[*piInfoCnt].iLevel = iLevel;
    pstPrintInfo[*piInfoCnt].iPos = iPos;

    (*piInfoCnt)++;
    iLevel++;
    
    make_print_info(pstRegex->pstChild, pstPrintInfo, piInfoCnt, iLevel, iPos - iPos/2);
    make_print_info(pstRegex->pstBrother, pstPrintInfo, piInfoCnt, iLevel, iPos + iPos/2);

    return;
} 

static int ComparePrintInfo(const void* pvInfo1, const void* pvInfo2)
{
    struct regex_group_print_info* pstInfo1 = NULL;
    struct regex_group_print_info* pstInfo2 = NULL;

    pstInfo1 = (struct regex_group_print_info*)pvInfo1;
    pstInfo2 = (struct regex_group_print_info*)pvInfo2;

    if (pstInfo1->iLevel != pstInfo2->iLevel)
    {
        return pstInfo1->iLevel - pstInfo2->iLevel;
    } 
    else
    {
        return pstInfo1->iPos - pstInfo2->iPos;
    } 
} 

// print regex tree according to regex analyse result 
void print_regex_tree(struct regex_group_t* pstRegex)
{
    struct regex_group_print_info astPrintInfo[100];
    int iInfoCnt = 0;
    int iI = 0;
    int iOldLevel = 0;
    int iOldPos = 0;
    int iSpaceCnt = 0;
    char* pcRegex = NULL;
    
    make_print_info(pstRegex, astPrintInfo, &iInfoCnt, 1, 60);

    qsort(astPrintInfo, iInfoCnt, sizeof(astPrintInfo[0]), ComparePrintInfo);

    for (iI = 0; iI < iInfoCnt; iI++)
    {
        if (astPrintInfo[iI].iLevel > iOldLevel)
        {
            printf("\n");
            iOldPos = 0;
        } 

        iSpaceCnt = astPrintInfo[iI].iPos - iOldPos;
        printf("%*s%d:%d:",iSpaceCnt , " ", astPrintInfo[iI].iPos, astPrintInfo[iI].iLevel);

        pcRegex = get_regex_str(astPrintInfo[iI].pstRegex);
        printf("%s", pcRegex);

        iOldLevel = astPrintInfo[iI].iLevel;
        iOldPos += strlen(pcRegex) + iSpaceCnt;
    } 

    printf("\n");

    return;
} 

